- Motivation
The NAG C Library [1] and
NAG Fortran Library [2] contain
many mathematical and statistical routines which are
useful for package builders. Areas covered include
linear algebra, optimization, quadrature, differential
equations, regression analysis, and time series analysis.
Although written in C or Fortran, the functionality of the
libraries can be accessed from other languages,
including C++, and on PCs, DLL versions of
the libraries can be exploited in many ways
[3].
It is natural, then, to wonder whether it is possible to call the
NAG Libraries from the Java programming language
[4].
For someone needing to perform numerical computations,
one approach is to create Java classes implementing the
required functionality; a group who have made progress in
this direction, partly by writing new code and partly by converting
pre-existing code from other languages into Java, is the
Numerics Working Group of the Java Grande Forum.
The JavaNumerics web page
[5]
gives much useful information, including discussion
of the difficulties of using Java for numerical computation
due to constraints imposed by Java as it currently stands.
In this report, we use the alternative
approach of calling the NAG Libraries directly from Java,
thus evading the job of writing or rewriting code,
and everything that that entails in the way of testing.
Of course, since we propose to call the NAG Libraries, our application
will no longer be portable in the sense that it would have been
had it been exclusively written in Java, because now it will rely
on the presence of a machine-dependent implementation of a NAG
Library at run time. However, it will still be portable in
the sense that the NAG Libraries are available on almost all
commercially significant machines.
Apart from avoiding the need to first write Java versions of
numerical routines, using the NAG Libraries has another advantage.
Java has been designed to be portable; a compiled program will run on any
machine which has an implementation of the Java Virtual Machine (VM).
To accomplish this, the Java compiler does not compile to
machine-dependent assembler, as do traditional languages such
as C or C++, but to a machine-independent byte code. This
byte code then gets interpreted at run time by the VM.
Although the Java interpreter is efficient, it is clear that it
would be hard for any interpreted program to run as fast
as a program compiled to assembler code. For many applications
this does not matter; but for applications that perform
cpu-intensive operations on large amounts of data, it may
be significant. By moving those operations out of Java and
into the NAG Libraries, we may therefore hope to cut execution
time.
In order to access the NAG Libraries from a Java program, we will
make use of the Java Native Interface.
- The Java Native Interface
The Java Native Interface (JNI), which comes as part of the
Java Software Development Kit (SDK), gives compile- and
run-time support to
anyone who would like to call native code from a Java
program. By native code, we mean non-Java code, typically
C or C++; in this report we will assume C.
At compile time, the JNI defines the way that Java data types
correspond to C data types – C programs get this information
from JNI header files that come with the Java SDK. A tool, javah,
that comes with the SDK, aids in creating application-specific header
files which aim to eliminate mistakes in communication
between Java and C routines.
At run time, the JNI allows the passing of Java objects
to the C code, and allows the C code access to
Java properties and methods. Thus, for example,
the C code can set properties of Java classes, and it is possible
to call a Java method from C.
During preparation of this report, we tested code on two
machines
-
a Sun machine running Solaris 8 (SunOS 5.8) with
Java 2 SDK, SE v1.2.2, plus
Sun Forte Developer 7 C version 5.4, Mark 7 of the
NAG C Library, and Mark 20 of the NAG Fortran Library
-
a PC running Windows XP with Java 2 SDK, SE v1.4.1, plus
Microsoft Visual C++ version 6.0,
Mark 7 of the NAG C Library, and Mark 20 of the NAG Fortran Library
Working on UNIX platforms other than Sun/Solaris should be
similar to Solaris; the main differences are likely to be in the
location of Java include files, and the
method of creating a shared object (dynamic library).
A good introduction to the Java Native Interface
can be found at the Sun Microsystems Java Tutorial web site
[6].
- Use of an interface library
Use of the JNI entails creation of an intermediate shared library
(on UNIX systems) or DLL (Microsoft Windows systems). This library
acts as the interface between the Java code and the NAG C Library
code.
The interface library is required because when a native method (i.e.
function or subroutine) is
called from Java, extra arguments are prepended to the argument list
of the native routine being called. These extra arguments give the
native code access to Java methods and properties, but of course
the NAG Libraries were not designed to handle these arguments.
Furthermore, the types of the arguments passed from Java
do not always correspond exactly to standard C or Fortran types, and so the
NAG Libraries cannot use them directly.
The interface library must handle these issues, make its
own calls to the NAG Library, and then send the results back to Java.
The Java Native Interface as a link between Java and a NAG Library
Implementation of a call from Java to a NAG Library is a
three-stage process
-
Write a declaration, in Java, for the native method. This declaration
will include the keyword native to signify to the Java compiler
that it will be implemented externally.
-
Create a header file for use by the native (C) code. This header file
contains the declaration of the native method as viewed by the
C compiler, i.e. it includes the extra arguments required for the
C function to access Java methods and properties, and also has
argument types defined in terms of standard C types.
-
Implement the native method in C. This function will use the header
file created above, make calls to the NAG C or Fortran Library and possibly
back to Java methods, and return results to Java. The C code
is compiled to build the interface library. Note that we implement
this code in C even when we intend to make use of the NAG Fortran
Library; because of the structure of the extra arguments mentioned
above it is not possible to write this "glue" code in Fortran.
When the interface library has been built, the Java code
that uses it is still machine-independent even though the
interface library is not. Thus, we need to
build the interface library on all platforms that we are
interested in, but we do not have to edit or rebuild the Java code
that uses it.
- Examples
The process of creating an interface library is most easily
understood by demonstration. We give four examples,
each showing different aspects of use of the JNI with the NAG Libraries.
-
4.1
Example 1
Bessel function Y0 (x)
|
The simplest possible example: we call a function with only one
return value – the Y0 (x)
Bessel function routine s17acc from the NAG C Library.
No special code is required to handle the single return value.
|
-
4.2
Example 2
Solving a system of linear equations A x = b
|
We call a function which returns an array of results –
the linear equation solver f04arc. Extra code is required to
get data from Java to C and results back from C to Java.
|
-
4.3
Example 3
Evaluating the definite integral of a user-supplied function f(x)
|
We call a function which requires a function as one of its arguments –
the quadrature routine d01ajc of the NAG C Library.
We demonstrate how the C code
can call back to a Java method to evaluate the function
to be integrated. Also, we will see how the C code can pass results
back to Java by modifying Java class properties.
|
-
4.3
Example 4
Solving a nonlinear minimization problem
|
This example shows how to call
the nonlinear minimization routine e04ucf of the NAG Fortran Library.
We demonstrate how the C interface code needs to handle calls
to Fortran and deal with callback routines from Fortran to C to Java.
We also need to take account of the way Fortran stores two-dimensional arrays.
|
- Building more interfaces
If you have studied all the examples above, you will have
learned the basic techniques for passing information
between Java and the NAG C and Fortran Libraries.
You should be able to use these
techniques, and perhaps re-use some of the source code presented here,
to create interfaces to many other of the routines in the NAG Library.
It should be relatively easy to enhance the interfaces presented,
for example to return an error message to Java when a NAG routine
has failed, instead of just returning an integer code.
If you are interested in calling NAG Fortran routines
from Java, NAG supplies header files [7]
that can help to make it easier to call NAG Fortran 77 Library
routines from an interface library written in C.
- References
- [1]
The NAG C Library Manual
Numerical Algorithms Group
Numerical Algorithms Group Limited, Oxford, UK, 2002.
http://www.nag.co.uk/numeric/cl/Manual/html/CLlibrarymanual.asp
- [2]
The NAG Fortran Library Manual
Numerical Algorithms Group
Numerical Algorithms Group Limited, Oxford, UK, 2001.
http://www.nag.co.uk/numeric/fl/manual/html/FLlibrarymanual.asp
- [3]
Enhancing the Numerical Capability of Your Application
Numerical Algorithms Group
Numerical Algorithms Group Limited, Oxford, UK, 2004.
http://www.nag.co.uk/numeric/Num_DLLhelp.asp
- [4]
Java 2 Platform, Standard Edition (J2SE) Documentation
Sun Microsystems
Sun Microsystems Inc. 1995-2004
http://java.sun.com/docs
- [5]
JavaNumerics
Ron Boisvert, Roldan Pozo
Java Numerics Working Group, 1998-2003.
http://math.nist.gov/javanumerics/
- [6]
Trail: Java Native Interface
Beth Stearns
Sun Microsystems Inc.
http://java.sun.com/docs/books/tutorial/native1.1/index.html
- [7]
Calling NAG Fortran Library Routines from C Language Programs
Using the NAG C Header Files
Ian Hounam
Numerical Algorithms Group Ltd, Oxford, UK, 2002
http://www.nag.co.uk/numeric/FL/FLassocinfo.asp#CH